package com.thiswhyme.seata.order.service;

import com.thiswhyme.common.expection.BusinessException;
import com.thiswhyme.common.response.ResponseVo;
import com.thiswhyme.seata.order.domain.Order;
import com.thiswhyme.seata.order.domain.OrderStatus;
import com.thiswhyme.seata.order.feign.AccountFeignService;
import com.thiswhyme.seata.order.feign.StorageFeignService;
import com.thiswhyme.seata.order.repository.OrderMapper;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author: thiswhyme
 * @date: 2020/9/4
 */
@Slf4j
@Service
public class OrderService {

    private static final int NO_HINT = 0;
    private static final int HINT_READ = 1;
    private static final int HINT_WRITE = 2;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private AccountFeignService accountFeignService;

    @Autowired
    private StorageFeignService storageFeignService;

    @GlobalTransactional
    public boolean placeOrder(Long userId, Long productId, Integer price) {
        Integer amount = 1;
        long random = (long) ((Math.random() * 9 + 1) * 1E16);
        Order order = new Order().setId(random).setUserId(userId)
                .setProductId(productId)
                .setStatus(OrderStatus.INIT)
                .setPayAmount(price);
        orderMapper.insert(order);

        log.info("保存订单{}", order.getId() != null ? "成功" : "失败");
        log.info("当前 XID: {}", RootContext.getXID());

        // 扣减库存
        log.info("开始扣减库存");
        ResponseVo<Boolean> storageResult = storageFeignService.reduceStock(productId, amount);
        log.info("扣减库存结果:{}", storageResult.getData());
        if(!storageResult.getData()) {
            throw new BusinessException("扣减库存失败");
        }

        // 扣减余额
        log.info("开始扣减余额");
        ResponseVo<Boolean> accountResult = accountFeignService.reduceBalance(userId, price);
        log.info("扣减余额结果:{}", accountResult.getData());
        if(!accountResult.getData()) {
            throw new BusinessException("扣减余额失败");
        }

        Integer updateOrderRecord = orderMapper.updateById(order.setStatus(OrderStatus.SUCCESS));
        log.info("更新订单:{} {}", order.getId(), updateOrderRecord > 0 ? "成功" : "失败");
        if(!(updateOrderRecord > 0)) {
            throw new BusinessException("更新订单状态失败");
        }

        return updateOrderRecord > 0;
    }

    public Order selectOrder(Long orderId, int hint) {
        Order order = null;
        if(NO_HINT == hint) {
            order = orderMapper.selectById(orderId, "");
            log.info("selectOrder====无hint结果：{}", order == null ? null : order.toString());
        } else if(HINT_READ == hint) {
            order = orderMapper.selectById(orderId, "/*#mycat:db_type=slave*/");
            log.info("selectOrder====hint从库：{}", order == null ? null : order.toString());
        } else if(HINT_WRITE == hint) {
            order = orderMapper.selectById(orderId, "/*#mycat:db_type=master*/");
            log.info("selectOrder====hint写库：{}", order == null ? null : order.toString());
        }
        return order;
    }

    @Transactional
    public Order selectOrderWithTx(Long orderId, int hint) {
        Order order = null;
        if(NO_HINT == hint) {
            order = orderMapper.selectById(orderId, "");
            log.info("selectOrderWithTx====无hint结果：{}", order == null ? null : order.toString());
        } else if(HINT_READ == hint) {
            order = orderMapper.selectById(orderId, "/*#mycat:db_type=slave*/");
            log.info("selectOrderWithTx====hint从库：{}", order == null ? null : order.toString());
        } else if(HINT_WRITE == hint) {
            order = orderMapper.selectById(orderId, "/*#mycat:db_type=master*/");
            log.info("selectOrderWithTx====hint写库：{}", order == null ? null : order.toString());
        }
        return order;
    }
}
